package com.netty.messagepack;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;

public class EchoServer {

    public void bind(int port){

        //NioEventLoopGroup是一个线程组，它包含了一组NIO线程，
        // 这里的两个线程组一个是用于服务端接受客户端的连接，
        // 另一个用于SocketChannel的网络读写
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            //netty用于启动NIO服务端的辅助启动类
            ServerBootstrap b = new ServerBootstrap();

            //设置线程组
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)//设置channel
                    .option(ChannelOption.SO_BACKLOG, 100)//设置channel的TCP参数
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000)
                    .childHandler(new ChildChannelHandler());//绑定IO事件处理类

            //绑定监听端口，调用同步阻塞方法等待绑定完成
            ChannelFuture f = b.bind(port).sync();
            //阻塞，等待服务端链路关闭后main函数才退出
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //优雅退出，释放跟shutdownGracefully相关联的所有资源
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {

        @Override
        protected void initChannel(SocketChannel serverSocket) throws Exception {
            serverSocket.pipeline().addLast("frameDecode",
                    new LengthFieldBasedFrameDecoder(65535, 0, 2,0,2));
            serverSocket.pipeline().addLast("msgpack decoder", new MsgpackDecoder());
            serverSocket.pipeline().addLast("frameEncode", new LengthFieldPrepender(2));
            serverSocket.pipeline().addLast("msgpack encoder", new MsgpackEncoder());
            serverSocket.pipeline().addLast(new EchoServerHandler());
        }
    }

    public static void main(String[] args) {
        int port = 30000;
        new EchoServer().bind(port);
    }
}

